package com.zimin.cloud.gateway.common;

import com.zimin.common.enums.Number;
import com.zimin.common.utils.Md5Util;
import lombok.extern.slf4j.Slf4j;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;

/**
 * 加密工具类
 * @author zimin
 */
@Slf4j
public class SignUtils {

    /**
     * 请求url的所有参数拼接成字符串
     *
     * @param map
     * @return
     */
    public static String createQueryString(Map<String, Object> map) {
        if (map.isEmpty()) {
            return null;
        }
        var res = new StringBuilder();
        for (String key : map.keySet()) {
            var value = String.valueOf(map.get(key));
            if (null == key || "".equals(key)) {
                continue;
            }
            try {
                if (null != value && !"".equals(value)) {
                    res.append(key).append("=").append(URLEncoder.encode(value, "UTF-8")).append("&");
                } else {
                    res.append(key).append("=").append(value).append("&");
                }
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        if (res.length() > 1) {
            return res.substring(0, res.length() - 1);
        }
        return null;
    }

    /**
     * 通过md5进行加密
     *
     * @param source 要加密的数据
     * @return
     * @throws NoSuchAlgorithmException
     */
    private static String getMd5(String source) throws NoSuchAlgorithmException {
        var digest = MessageDigest.getInstance("md5");
        var bytes = source.getBytes();
        var targetBytes = digest.digest(bytes);
        var characters = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
        var builder = new StringBuilder();
        for (byte b : targetBytes) {
            var high = (b >> 4) & 15;
            var low = b & 15;
            var highChar = characters[high];
            var lowChar = characters[low];
            builder.append(highChar).append(lowChar);
        }

        return builder.toString();
    }

    /**
     * 进行MD5加密
     *
     * @param qs
     * @param time
     * @param salt
     * @return
     */
    public static String getSign(String qs, long time, String salt) {
        try {
            return getMd5(String.format("%s&time=%d&salt=%s", qs, time, salt));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 功能：将一个Map按照Key字母升序构成一个QueryString. 并且加入时间混淆的hash串
     *
     * @param queryMap query内容
     * @param time     加密时候，为当前时间；解密时，为从querystring得到的时间；
     * @param salt     加密salt
     * @return
     */
    public static String createHashedQueryString(Map<String, Object> queryMap, long time, String salt) {
        queryMap.remove("timestamp");
        queryMap.remove("salt");
        var qs = createQueryString(queryMap);
        if (qs == null) {
            return null;
        }
        time = time / 1000;
        var hash = getSign(qs, time, salt).toUpperCase();
        var thqs = String.format("%s&time=%d&hash=%s", qs, time, hash);
        log.info("加密前字符串:{}", thqs);
        return Md5Util.encrypt(thqs);
    }

    public static void main(String[] args) {
        // 需要传递的参数
        Map<String, Object> params = new HashMap<>(Number.TEN.getIntNum());
        params.put("current", "1");
        params.put("size", "10");
        //秘钥
        String salt = "LASD8SD8SDN234";
        //当前时间戳
        long time = 1639564672418L;
        System.out.println(time);
        //生成http请求参数
        String str = createHashedQueryString(params, time, salt);
        System.out.println("加密后的字符串:" + str);

    }

}